Skip to content

[pull] main from MetaMask:main#495

Merged
pull[bot] merged 18 commits into
Reality2byte:mainfrom
MetaMask:main
Feb 3, 2026
Merged

[pull] main from MetaMask:main#495
pull[bot] merged 18 commits into
Reality2byte:mainfrom
MetaMask:main

Conversation

@pull
Copy link
Copy Markdown

@pull pull Bot commented Feb 3, 2026

See Commits and Changes for more details.


Created by pull[bot] (v2.0.0-alpha.4)

Can you help keep this open source service alive? 💖 Please sponsor : )

georgeweiler and others added 18 commits February 3, 2026 07:39
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

TokenListItem tests are failing.

https://github.com/MetaMask/metamask-mobile/actions/runs/21614511374/job/62290254653?pr=25557

This is a fix.

```
Error: app/components/UI/Tokens/TokenList/TokenListItem/TokenListItem.test.tsx(1043,10): error TS2741: Property 'shouldShowTokenListItemCta' is missing in type '{ assetKey: FlashListAssetKey; showRemoveMenu: Mock<any, any, any>; setShowScamWarningModal: Mock<any, any, any>; privacyMode: false; }' but required in type 'TokenListItemProps'.
Error: app/components/UI/Tokens/TokenList/TokenListItem/TokenListItem.test.tsx(1070,10): error TS2741: Property 'shouldShowTokenListItemCta' is missing in type '{ assetKey: FlashListAssetKey; showRemoveMenu: Mock<any, any, any>; setShowScamWarningModal: Mock<any, any, any>; privacyMode: false; }' but required in type 'TokenListItemProps'.
Error: Process completed with exit code 2.
```

<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->

## **Changelog**

<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`

If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`

(This helps the Release Engineer do their job more quickly and
accurately)
-->

CHANGELOG entry: null

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: my feature name

  Scenario: user [verb for user action]
    Given [describe expected initial app state]

    When user [verb for user action]
    Then [describe expected outcome]
```

## **Screenshots/Recordings**

<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->

### **Before**

<!-- [screenshots/recordings] -->

### **After**

<!-- [screenshots/recordings] -->

## **Pre-merge author checklist**

- [ ] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [ ] I've completed the PR template to the best of my ability
- [ ] I've included tests if applicable
- [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [ ] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.


<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk: test-only change that wires a newly-required prop into
`TokenListItem` render calls, with no runtime behavior impact.
> 
> **Overview**
> Fixes failing `TokenListItem` unit tests by passing the required
`shouldShowTokenListItemCta` prop in the stablecoin lending CTA
scenarios, aligning the test renders with the updated
`TokenListItemProps` type.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
571ac1c. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description**

Prepping for season 2 by reworking the season status banner. In figma
this is the design:

<img width="1280" height="527" alt="image"
src="https://github.com/user-attachments/assets/6a9514ae-5d94-4e93-9020-f5fb7cd835c4"
/>

## **Changelog**

CHANGELOG entry: add rewards season 2 season status banner

## **Screenshots/Recordings**

### **After**

Loading
<img width="829" height="278" alt="image"
src="https://github.com/user-attachments/assets/686e7022-da07-4f68-9a30-6e34dd7d48d3"
/>

Loaded
<img width="913" height="188" alt="image"
src="https://github.com/user-attachments/assets/c9f7fe67-c067-44e5-b35c-dbc61934f4f9"
/>


Error
<img width="832" height="376" alt="image"
src="https://github.com/user-attachments/assets/2b61d856-8f5c-403d-b197-b608dd70fc35"
/>




<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Medium risk because it rewrites the `SeasonStatus` UI and its
loading/error rendering paths, which can easily introduce
layout/regression issues and incorrect state handling. No auth or
sensitive data logic is changed.
> 
> **Overview**
> Updates the Rewards dashboard to render a redesigned `SeasonStatus`
banner with horizontal layout, themed background, and season name + time
remaining on the right.
> 
> Reworks `SeasonStatus` to remove tier/progress/level-up UI and the
image modal, simplify loading to a smaller skeleton, and keep the error
banner with retry calling `fetchSeasonStatus`.
> 
> Adds/updates unit tests to match the new banner behavior and
introduces a new i18n string `rewards.season_status.points_earned` while
removing old season-status copy (`rewards.points`, `rewards.point`,
`rewards.to_level_up`) from `en.json`.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
b6a1eab. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
## **Description**

Makes `prices.prewarm()` non-blocking to improve Perps home screen load
time.

**Problem:** The `prices.prewarm()` method was blocking initialization
by awaiting `getMarkets()` before returning, causing users to wait for
all 269 market symbols to load before seeing any UI.

**Solution:** Convert to fire-and-forget pattern - return the cleanup
function immediately while market fetching and subscription happen in
the background.

## **Changelog**

CHANGELOG entry: Improved Perps home screen load time by making price
prewarming non-blocking

## **Related issues**

Fixes: N/A (Performance optimization)

## **Manual testing steps**

```gherkin
Feature: Perps load time optimization

  Scenario: User opens Perps home screen
    Given the user is on the main wallet screen

    When user navigates to Perps home screen
    Then the screen should load faster (UI becomes interactive sooner)
    And prices should appear after a brief delay as background fetch completes
    And no errors should appear in console

  Scenario: User leaves Perps before prices load
    Given the user just opened Perps home screen

    When user navigates away before prices appear
    Then no errors should occur
    And no orphaned subscriptions should remain
```

## **Screenshots/Recordings**

### **Before**

N/A - Performance improvement, no visual changes

### **After**

N/A - Performance improvement, no visual changes

## **Pre-merge author checklist**

- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I've included tests if applicable
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Changes the lifecycle of the Perps price WebSocket subscription to be
asynchronous, which could affect when/if price updates start and how
cleanup behaves under rapid navigation. Added tests reduce risk but
regressions could still impact pricing display and connection stability.
> 
> **Overview**
> Improves Perps home load time by making `PriceStreamChannel.prewarm()`
return a cleanup function immediately, while `getMarkets()` and the
all-markets `subscribeToPrices` setup run in the background.
> 
> Adds leak/race protections for rapid enter/exit flows (cycle ID to
ignore stale `getMarkets()` resolutions, separate tracking of the
*actual* unsubscribe), and hardens error handling to log background
fetch failures and recover by resetting state and reconnecting active
subscribers. Updates tests to cover the new non-blocking behavior,
cleanup-before-fetch, stale-promise suppression, and error paths.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
df2a28b. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

https://consensyssoftware.atlassian.net/jira/software/c/projects/RWDS/boards/3533?selectedIssue=RWDS-582
Supports bulk link all accounts to a Rewards subscription through a
redux saga.

**Features:**
- Navigation-independent: runs at the saga level, so it continues across
navigation.
- Real-time progress: processes accounts sequentially and updates Redux
after each account.
- Batch optimization: fetches opt-in status for all addresses in one
call before processing.

**Performance tuning:**
- Cache invalidation every 100 accounts (and on the last account)
- Yields to UI thread every 2 accounts to prevent freezing
- Early abort after 5 consecutive failures
- Error handling: per-account errors don't stop the process; failures
are tracked individually.
- Cancellation support: can be cancelled via BULK_LINK_CANCEL action.

**Architecture:**
- bulkLinkWorker: main orchestration saga
- watchBulkLink: watcher that handles start/cancel actions
- Helper functions: account collection, batch status fetching,
individual account linking
- Action creators: startBulkLink() and cancelBulkLink() exported for
backwards compatibility

**Flow:**
- Collect all supported accounts from all account groups
- Batch fetch opt-in status for all addresses
- Filter to accounts that need linking
- Process accounts one-by-one with progress updates
- Complete with success/failure statistics

This enables bulk linking with progress tracking and UI responsiveness.
<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->

## **Changelog**

<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`

If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`

(This helps the Release Engineer do their job more quickly and
accurately)
-->

CHANGELOG entry: Allow user to opt-in all accounts at once to Rewards

## **Related issues**

Fixes: null

## **Manual testing steps**

```gherkin
Feature: my feature name

  Scenario: user [verb for user action]
    Given [describe expected initial app state]

    When user [verb for user action]
    Then [describe expected outcome]
```

## **Screenshots/Recordings**

<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->

### **Before**

<!-- [screenshots/recordings] -->

### **After**
<img width="1179" height="2556" alt="Simulator Screenshot - E2E Test -
2026-01-09 at 13 27 24"
src="https://github.com/user-attachments/assets/be74f5a6-1920-4254-abd5-6a94e45ed1d3"
/>
<img width="1179" height="2556" alt="Simulator Screenshot - E2E Test -
2026-01-08 at 21 30 31"
src="https://github.com/user-attachments/assets/f3524bbd-3cf2-48d4-83df-be21fa8030c5"
/>
<img width="1179" height="2556" alt="Simulator Screenshot - E2E Test -
2026-01-08 at 21 06 18"
src="https://github.com/user-attachments/assets/09c0bbde-ac22-4188-8d50-eae83ef86d76"
/>
<img width="1179" height="2556" alt="Simulator Screenshot - E2E Test -
2026-01-08 at 20 58 04"
src="https://github.com/user-attachments/assets/ffb80a96-ba22-4d4c-83b1-11fb1d5ff8ed"
/>

<!-- [screenshots/recordings] -->

## **Pre-merge author checklist**

- [x] I’ve followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I’ve included tests if applicable
- [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I’ve applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

- [x] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [x] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.


<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Changes Rewards opt-in/opt-out and settings behaviors by introducing a
new bulk-link saga integration, auto-resume on focus, and UI gating
while bulk linking; issues could impact account linking state and user
onboarding flows.
> 
> **Overview**
> Adds a new `useBulkLinkState` hook that exposes bulk-link lifecycle
actions (`start/cancel/resume/reset`) plus progress/summary fields
sourced from Redux selectors, with comprehensive unit tests.
> 
> Extends Rewards onboarding to optionally *opt-in all accounts*:
`OnboardingStep4` and `OnboardingNoActiveSeasonStep` add a checkbox and
pass `bulkLink` into `useOptin`, which now cancels any running bulk link
before opting in, tracks a `bulk_link` metrics property, and starts bulk
linking on successful opt-in instead of linking a single account group.
> 
> Improves Rewards settings UX during bulk linking:
`RewardSettingsAccountGroupList` adds a progress section with a progress
bar and an “Add all accounts” button (wired to `startBulkLink`), plus
per-wallet expand/collapse (“Show more/less”). Individual account-group
link buttons are disabled while bulk linking is running, and
`RewardSettingsAccountGroup` shows a loading indicator when linking.
> 
> Adds resilience/guardrails: `RewardsDashboard` auto-resumes an
interrupted bulk link on screen focus, `useRewardDashboardModals`
suppresses the unlinked-accounts modal while bulk linking is running,
`useOptout` cancels bulk linking before opt-out, and
`Authentication.resetWalletState` dispatches `cancelBulkLink()` before
resetting Rewards state. Tests are updated/expanded accordingly.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
c07b6a3. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Rik Van Gulck <vangulckrik@gmail.com>
…5533)

<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**
Following #24313 we're
looking to centralize all tools and test resources in one place.
This PR moves spec files for `Notifications`, `Identity` and
`Multichain-accounts` specs to `/tests`.

Previous related PRs:
- #24988
- #24313
- #25031
- #25095
- #25167
- #25198
- #25219
- #25263
- #25279
- #25520


<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->

## **Changelog**

<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`

If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`

(This helps the Release Engineer do their job more quickly and
accurately)
-->

CHANGELOG entry:

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: my feature name

  Scenario: user [verb for user action]
    Given [describe expected initial app state]

    When user [verb for user action]
    Then [describe expected outcome]
```

## **Screenshots/Recordings**

<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->

### **Before**

<!-- [screenshots/recordings] -->

### **After**

<!-- [screenshots/recordings] -->

## **Pre-merge author checklist**

- [ ] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [ ] I've completed the PR template to the best of my ability
- [ ] I've included tests if applicable
- [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [ ] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.


<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk: changes are confined to test code and Jest configuration,
but broad import-path rewrites could still break CI test discovery or
shared helpers if any path is missed.
> 
> **Overview**
> Moves Identity, Notifications, Multichain Accounts (and related
network) E2E/spec coverage under `tests/` and updates a wide set of
specs/helpers to import shared pages, tags, fixtures, mocks, and
utilities from the new locations.
> 
> Updates test infrastructure references accordingly (e.g., notification
mock helpers now sourced from `tests/smoke/notifications/...`) and
tweaks `package.json` `test:unit` to run `jest` against
`./tests/**/*.test.ts` instead of `./e2e/**/*.test.ts`, reflecting the
new test layout.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
e7ef33f. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

Allow the RampsController messenger to call RampsService:getGeolocation
by adding it to the delegated actions in ramps-controller-messenger.
This lets the controller resolve the user’s region/geolocation for ramps
flows (e.g. when no region is set).

<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->

## **Changelog**

<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`

If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`

(This helps the Release Engineer do their job more quickly and
accurately)
-->

CHANGELOG entry: null

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: my feature name

  Scenario: user [verb for user action]
    Given [describe expected initial app state]

    When user [verb for user action]
    Then [describe expected outcome]
```

## **Screenshots/Recordings**

<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->

### **Before**

<!-- [screenshots/recordings] -->

### **After**

<!-- [screenshots/recordings] -->

## **Pre-merge author checklist**

- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [ ] I've included tests if applicable
- [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk: a single additional delegated messenger action is exposed,
with no changes to business logic or data flow beyond enabling an
existing service call.
> 
> **Overview**
> **Exposes geolocation lookup to ramps flows.**
> 
> `getRampsControllerMessenger` now delegates
`RampsService:getGeolocation` to the `RampsController` messenger,
allowing the controller to request user region when needed alongside the
existing delegated ramps service actions.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
89ccbe7. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

Co-authored-by: Amitabh Aggarwal <aggarwal.amitabh@gmail.com>
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->

Quick refactor based on code review from
#25296

- Call useHydrateRampsController() from the Ramps renderless component
(FiatOrders in app/components/UI/Ramp/index.tsx) instead of the Wallet
view.

- Remove the hook from Wallet and keep hydration tied to when the Ramps
component mounts (e.g. via Main nav).

## **Changelog**

<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`

If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`

(This helps the Release Engineer do their job more quickly and
accurately)
-->

CHANGELOG entry: null

## **Related issues**

Fixes:

#25296 (comment)

## **Manual testing steps**

```gherkin
Feature: my feature name

  Scenario: user [verb for user action]
    Given [describe expected initial app state]

    When user [verb for user action]
    Then [describe expected outcome]
```

## **Screenshots/Recordings**

<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->

### **Before**

<!-- [screenshots/recordings] -->

### **After**

<!-- [screenshots/recordings] -->

## **Pre-merge author checklist**

- [ ] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [ ] I've completed the PR template to the best of my ability
- [ ] I've included tests if applicable
- [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [ ] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.


<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Changes when `RampsController.hydrateState()` runs by moving hydration
from `Wallet` mount to `FiatOrders` (`Ramp`) mount, which could affect
ramps data readiness/timing in some navigation flows.
> 
> **Overview**
> Moves ramps state hydration into the renderless `FiatOrders` component
by invoking `useHydrateRampsController()` when the Ramp module mounts,
and removes the same hook call from `Wallet`.
> 
> Updates unit tests to reflect the new ownership: `Ramp/index.test.tsx`
now mocks the hydration hook, and `Wallet/index.test.tsx` no longer
provides a mocked `RampsController.hydrateState`.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
1aae695. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

The very first iteration of the ramps controller used a string as the
user's region (such as `"us-ca"`). The region is now an object with
information about the users region.

This migration will set any legacy users' region to `null` which will
ensure the controller resets the region to the correct interface.


<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->

## **Changelog**

<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`

If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`

(This helps the Release Engineer do their job more quickly and
accurately)
-->

CHANGELOG entry: null

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: my feature name

  Scenario: user [verb for user action]
    Given [describe expected initial app state]

    When user [verb for user action]
    Then [describe expected outcome]
```

## **Screenshots/Recordings**

<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->

### **Before**

<!-- [screenshots/recordings] -->

### **After**

<!-- [screenshots/recordings] -->

## **Pre-merge author checklist**

- [ ] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [ ] I've completed the PR template to the best of my ability
- [ ] I've included tests if applicable
- [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [ ] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk: adds a defensive Redux-state migration and unit tests; the
main risk is incorrect shaping of persisted `RampsController.userRegion`
for legacy users, but it fails closed by returning the original state
and capturing exceptions.
> 
> **Overview**
> Adds migration **116** to normalize persisted
`engine.backgroundState.RampsController.userRegion` to the current
`UserRegion | null` shape.
> 
> Legacy `userRegion` strings are reset to `null` (so the controller
geolocates on init), and prior `ResourceState`-shaped values are
replaced with their `.data` payload; missing/invalid controller/state
shapes are left unchanged and failures are reported to Sentry. Includes
Jest coverage for the migration paths and registers the migration in
`app/store/migrations/index.ts`.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
ffe9bac. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->

The `AnalyticsEventProperties` type does not accept `undefined` values
in property objects. When objects with optional or undefined properties
were spread into analytics events, it caused type mismatches and
potential tracking errors.

Context/History: Analytics Controller require no undefined values
because our analytics system, including Segment, are not able to handle
them. This leads to errors. We want to enforce strict value quality.

**Solution:**
- Created a new utility function `filterUndefinedValues()` that removes
`undefined` values from objects before passing them to analytics
- Updated `AnalyticsEventBuilder.addProperties()` and
`addSensitiveProperties()` to automatically filter undefined values from
property objects
- Added comprehensive JSDoc documentation to `AnalyticsEventBuilder`
explaining the requirement and usage
- Included full test coverage for the utility function

## **Changelog**

<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`

If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`

(This helps the Release Engineer do their job more quickly and
accurately)
-->

CHANGELOG entry: null

## **Related issues**

Fixes: #24557
Fixes: https://consensyssoftware.atlassian.net/browse/MCWP-317
## **Manual testing steps**

```gherkin
Feature: Analytics tracking with filtered properties

  Scenario: user performs actions that trigger analytics events
    Given the app is installed and running
    And analytics tracking is enabled
    
    When user performs various actions across the app (restore wallet, edit account, deeplinks, etc.)
    Then analytics events are tracked successfully without undefined property values
    And no type errors occur in analytics event building
    And all valid property values (including null, 0, false, empty strings) are preserved
```

## **Screenshots/Recordings**

<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->

### **Before**

<!-- [screenshots/recordings] -->
Not applicable - this is an internal refactoring with no UI changes

### **After**

<!-- [screenshots/recordings] -->
Not applicable - this is an internal refactoring with no UI changes

## **Pre-merge author checklist**

- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I've included tests if applicable
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.



<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Broad refactor of analytics property handling across multiple
controllers and event sources; while behavior should be safer, it can
subtly change which properties are emitted (e.g., dropping `undefined`
keys) and could impact downstream metrics if incorrect.
> 
> **Overview**
> Centralizes analytics property sanitization by introducing
`AnalyticsUnfilteredProperties` and `filterUndefinedValues()`, and
updating
`AnalyticsEventBuilder.addProperties()`/`addSensitiveProperties()` to
automatically strip `undefined` values (treating `null`/`undefined`
inputs as empty).
> 
> Refactors multiple analytics call sites (Ramp, app-open attribution,
deep link analytics, bridge/snaps/network/DeFi/smart-tx controllers, and
transaction metrics) to pass properties directly (or as
`AnalyticsUnfilteredProperties`) and removes ad-hoc filtering/casting.
Updates `buildAndTrackEvent` and associated tests, and adds unit tests
for `filterUndefinedValues`.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
962d300. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

Fix unstable RemoteImage test

<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->

## **Changelog**

<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`

If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`

(This helps the Release Engineer do their job more quickly and
accurately)
-->

CHANGELOG entry: null

## **Related issues**

Fixes: https://consensyssoftware.atlassian.net/browse/SWAPS-3913

## **Manual testing steps**

N/A - see unit tests

## **Screenshots/Recordings**

<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->

### **Before**

N/A 

### **After**

N/A 

## **Pre-merge author checklist**

- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I've included tests if applicable
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk because changes are limited to test timing/synchronization
logic, but could mask real regressions if `waitFor` timeouts are too
lenient or fake timers interact with async updates differently.
> 
> **Overview**
> Stabilizes `RemoteImage` tests by wrapping snapshot and
presence/assertion checks in `waitFor` so expectations run after async
state updates (IPFS resolution, error state changes, and rerenders).
> 
> Improves timer determinism in the *Image Dimensions* suite by using
fake timers, clearing pending timers before manual `onLoad` calls, and
adding stronger cleanup (`runOnlyPendingTimers`, `useRealTimers`,
`restoreAllMocks`) to reduce flaky cross-test leakage.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
ae8539b. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…essenger pattern (#25421)

## **Description**

Migrate PredictController from the legacy `Engine.context` pattern to
the modern messenger architecture pattern for proper controller
architecture alignment.

**Why this change?**
- Align with MetaMask's controller architecture standards
- Enable proper dependency injection and testability
- Remove direct coupling to Engine singleton
- Follow the same pattern as other migrated controllers (e.g.,
PerpsController)

**What changed?**
- Replaced all `Engine.context` usages with `this.messenger.call()` for:
  - `KeyringController`: signTypedMessage, signPersonalMessage
- `NetworkController`: findNetworkClientIdByChainId,
getNetworkClientById
  - `RemoteFeatureFlagController`: getState
  - `AccountTreeController`: getAccountsFromSelectedAccountGroup
- Updated messenger factory delegation with new actions
- Updated all tests to use messenger mocks instead of Engine mocks

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes: https://consensyssoftware.atlassian.net/browse/PRED-163

## **Manual testing steps**

```gherkin
Feature: PredictController messenger migration

  Scenario: Prediction markets functionality works after migration
    Given the app is running with prediction markets enabled

    When user navigates to prediction markets
    Then markets should load correctly
    And user can view market details
    And trading functionality works as expected
```

## **Screenshots/Recordings**

### **Before**

N/A - Internal refactoring, no UI changes

### **After**

N/A - Internal refactoring, no UI changes

## **Pre-merge author checklist**

- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I've included tests if applicable
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Refactors `PredictController` to route signing, network-client lookup,
account selection, and remote feature flags through the messenger, so
mis-delegation or mismatched action signatures could break
trading/claim/deposit flows at runtime.
> 
> **Overview**
> `PredictController` is migrated off the legacy `Engine.context`
singleton to the messenger pattern, replacing direct calls to
`KeyringController`, `NetworkController`, and
`RemoteFeatureFlagController` with `this.messenger.call(...)` and
subscribing to `RemoteFeatureFlagController:stateChange`.
> 
> Signer/account selection is updated to derive the active EVM address
via `AccountTreeController:getAccountsFromSelectedAccountGroup` (using
`isEvmAccountType`), and network cache invalidation now resolves the
appropriate network client via messenger
(`findNetworkClientIdByChainId`/`getNetworkClientById`).
> 
> Tests are refactored to remove `Engine` mocks and instead register
messenger action handlers for the new dependencies, including updated
expectations around network client IDs and remote feature flag state
injection.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
bcfc727. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…25023)

<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

Disable swap max button on native assets when stx is disabled

<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->

## **Changelog**

<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`

If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`

(This helps the Release Engineer do their job more quickly and
accurately)
-->

CHANGELOG entry: disable swap max button on native assets when stx is
disabled

## **Related issues**

Fixes: https://consensyssoftware.atlassian.net/browse/SWAPS-3575

## **Manual testing steps**

```gherkin
Ensure that when smart transactions are disabled from settings,
when users try to swap a native asset, the max button is not rendered in quick keypad options
or next to source balance.
```

## **Screenshots/Recordings**

<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->

### **Before**

<!-- [screenshots/recordings] -->

### **After**

<!-- [screenshots/recordings] -->

## **Pre-merge author checklist**

- [x] I’ve followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I’ve included tests if applicable
- [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I’ve applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Changes the conditions under which users can select `Max` for
swaps/bridge inputs, which can affect amount entry behavior for native
assets across EVM/non-EVM chains. Also switches production-environment
detection to a different env var, which could impact build/test gating
if misconfigured.
> 
> **Overview**
> Prevents showing the swap/bridge **`Max` amount** option for *native
assets* unless Smart Transactions are enabled, while still allowing it
for non-native tokens. This logic is centralized in a new
`useShouldRenderMaxOption` hook that also suppresses the option on zero
balances and for non‑EVM native assets (where fees can’t be
precomputed).
> 
> Wires `isQuoteSponsored` into `SwapsKeypad`/`TokenInputArea` so
sponsored quotes can still allow `Max` when Smart Transactions are
active, and updates/expands unit tests accordingly.
> 
> Separately updates `isProduction()` (and its tests) to use
`METAMASK_ENVIRONMENT` instead of `NODE_ENV`, and adjusts the gasless
swap smoke test to mock Smart Transactions remote feature flags.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
7d6a9ba. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Davide Brocchetto <davide.brocchetto@consensys.net>
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

**Problem:** The price displayed in the order book page header remained
static (e.g., `$107.22`) even when the actual price was changing in the
order book and on the market detail page. After a few seconds, there was
a significant delta between the header price and the actual price,
making the order book confusing and untrustworthy for users.

**Root Cause:** The header price was derived from static market data via
`usePerpsMarkets()` which doesn't update in real-time. Meanwhile, the
order book itself was correctly subscribed to real-time updates via
`usePerpsLiveOrderBook`.

**Solution:** Added subscription to `usePerpsLivePrices` hook in
`PerpsOrderBookView` to get real-time price updates for the header
display. The implementation uses the live price with a fallback to the
static market price if the live data is not yet available.

## **Changelog**

CHANGELOG entry: Fixed order book header price not updating in real-time

## **Related issues**

Fixes: https://consensyssoftware.atlassian.net/browse/TAT-2441

## **Manual testing steps**

```gherkin
Feature: Order book live price header

  Scenario: User views order book and price updates in real-time
    Given user is on the Perps order book view for any asset (e.g., BTC)

    When the market price changes
    Then the price displayed in the header should update in real-time
    And the header price should match the order book mid price
    And there should be no significant delay between header and order book prices
```

## **Screenshots/Recordings**

### **Before**

Price in header stays static at initial value (e.g., $107.22) while
order book prices update

### **After**

Price in header now updates in real-time along with the order book data



https://github.com/user-attachments/assets/554df32b-441e-48a7-ab72-5376f3a53baf



## **Pre-merge author checklist**

- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I've included tests if applicable
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

- [x] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [x] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk UI-only change that adds a throttled `usePerpsLivePrices`
subscription for the header price; main risk is incorrect
fallback/validation causing a wrong displayed price, now covered by
tests.
> 
> **Overview**
> Fixes the Perps order book header price staying static by subscribing
to `usePerpsLivePrices` and deriving a `currentPrice` that prefers
validated live data and falls back to the parsed market price.
> 
> Updates `PerpsOrderBookView` tests to mock live prices and to cover
subscription params, price fallback/invalid-data handling, and close
interactions for the spread tooltip, depth band sheet, and geo-block
modal.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
81a8652. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## Description

This PR implements a first version of the Snapshots feature for Season 2
of MetaMask Rewards. Snapshots are time-limited token reward
opportunities that users can view and participate in.

## Changelog

CHANGELOG entry: null

## Screenshots/Recordings

**Overview content (all active/upcoming)**

<img width="939" height="1022" alt="image"
src="https://github.com/user-attachments/assets/77815598-5b17-4535-8df9-2ad0d7844201"
/>

<img width="939" height="1538" alt="image"
src="https://github.com/user-attachments/assets/b0f8a553-c445-4774-bc2b-8a15009040fd"
/>

<img width="939" height="1538" alt="image"
src="https://github.com/user-attachments/assets/9ee33abd-e0a2-401a-9990-1d5902e26660"
/>

**Dedicated Snapshot tab (all)**

<img width="939" height="1538" alt="image"
src="https://github.com/user-attachments/assets/42ab8ffc-92d5-4f58-a40e-8f350177d113"
/>

<img width="939" height="1538" alt="image"
src="https://github.com/user-attachments/assets/6c5233b6-8591-452e-8824-ebd5879d3311"
/>

<img width="939" height="1538" alt="image"
src="https://github.com/user-attachments/assets/191af1bc-a9f5-481e-99d5-be581c93a100"
/>

<img width="939" height="1538" alt="image"
src="https://github.com/user-attachments/assets/05b5bda6-8008-48a8-9261-b36f4b103993"
/>


<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Adds a new rewards data flow (API + controller caching + Redux
storage) and new UI surfaces gated by a feature flag; main risk is
regressions in tab state/analytics and snapshot fetching/caching
behavior.
> 
> **Overview**
> Adds the Season 2 *Snapshots* experience: a new `Snapshots` tab
(replacing `Levels`) plus an Overview `SnapshotsSection`, both gated by
`selectSnapshotsRewardsEnabledFlag` and with logic to reset `activeTab`
to `overview` if the tab becomes unavailable.
> 
> Implements end-to-end snapshots data support:
`RewardsController:getSnapshots` with 5-minute per-season caching and a
new `RewardsDataService:getSnapshots` call to
`/v1/seasons/:seasonId/snapshots`, alongside new UI hook `useSnapshots`
that fetches, stores, and categorizes snapshots
(active/upcoming/previous) for rendering.
> 
> Introduces snapshot UI components (`SnapshotTile`, condensed upcoming
tile, grouped lists) and status/date utilities, expands
`RewardsView.constants` test IDs, updates `RewardsThemeImageComponent`
to accept `resizeMode`, and refreshes/removes/adds tests to match the
new tab/feature-flag behavior.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
315fcfd. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**
Fix: Prevent crash caused by Notifee BlockStateBroadcastReceiver during
cold start

## Summary

Fixes a crash that occurs when notification permission changes trigger
Notifee's `BlockStateBroadcastReceiver` before React Native is fully
initialized during app cold start.

## Solution

Disable Notifee's `BlockStateBroadcastReceiver` by adding an override in
`AndroidManifest.xml`. This is the most light weight solution.

Changes (Background Tracking Only):
User Changes Settings OUTSIDE the App
Before (with receiver enabled):
1. User closes MetaMask
2. User goes to Android Settings → Apps → MetaMask → Notifications
3. User toggles "Allow notifications" OFF
4. BlockStateBroadcastReceiver fires immediately
**5. MetaMask knows about the change (while app is closed)**

After (with receiver disabled):
1. User closes MetaMask
2. User goes to Android Settings → Apps → MetaMask → Notifications
3. User toggles "Allow notifications" OFF
4. Nothing happens in the background
**5. MetaMask detects the change next time app opens**

Builds to test:
Crash version:
https://app.bitrise.io/build/f78866d9-cb88-4789-8be0-dec2d7c18e20
Fixed version:
https://app.bitrise.io/build/cd177e81-6545-44ff-a20f-6c5ed11936b5?tab=artifacts

<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->

## **Changelog**

<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`

If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`

(This helps the Release Engineer do their job more quickly and
accurately)
-->

CHANGELOG entry:Fix: Prevent crash caused by Notifee
BlockStateBroadcastReceiver during cold start

## **Related issues**

Fixes: [Fix: Prevent crash caused by Notifee BlockStateBroadcastReceiver
during cold start
](#25524)

## **Manual testing steps**

```gherkin
Scenario: App launches successfully when notification permission is disabled in Android Settings during cold start (After Fix)
  Given the MetaMask app is completely closed
  When I open Android Settings
  And I navigate to "Apps" → "MetaMask" → "Notifications"
  And I toggle "Allow notifications" to OFF
  And I return to the home screen
  And I tap the MetaMask app icon to launch it
  Then the app should launch successfully
  And I should not see any crash dialogs
  And I should see the wallet home screen
```

## **Screenshots/Recordings**

<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->

### **Before**

![crashed](https://github.com/user-attachments/assets/5031a720-dec4-4b4a-9daa-3fc0f19a9847)

### **After**
![no
crash](https://github.com/user-attachments/assets/7be5a943-e477-4379-8678-994584e116a6)


<!-- [screenshots/recordings] -->

## **Pre-merge author checklist**

- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I've included tests if applicable
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

- [x] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [x] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.


<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Disabling an Android broadcast receiver can change
notification-permission change handling while the app is closed;
otherwise changes are limited to build number bumps.
> 
> **Overview**
> Prevents an Android cold-start crash by **disabling Notifee’s**
`app.notifee.core.BlockStateBroadcastReceiver` via an
`AndroidManifest.xml` override, so it no longer runs before React Native
is initialized.
> 
> Also bumps the shared build/version code from `3418` to `3607` across
Android (`build.gradle`), iOS (`CURRENT_PROJECT_VERSION`), and CI
(`bitrise.yml`).
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
c944618. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: metamaskbot <metamaskbot@users.noreply.github.com>
#25467)

## **Description**

When users navigate to the Activity tab after completing a send or swap
transaction, the new transaction does not appear at the top of the list
unless they manually scroll up. The transaction list updates with the
correct data, but the view remains scrolled to its previous position,
causing confusion as users don't see their latest transaction.

**Improvement/solution:**
Implemented automatic scroll-to-top functionality when new transactions
are added to the Activity tab. Created a reusable
`useTransactionAutoScroll` custom hook that:

- Detects when new transactions are added to the list (either list
growth or first item change)
- Automatically scrolls to the top to show the latest transaction
- Prevents disruptive scrolling when users are manually browsing the
list
- Works across all supported networks (EVM, Solana, Bitcoin, Tron)
- Includes robust error handling and memory leak prevention

## **Changelog**

CHANGELOG entry: Fixed transaction list not automatically scrolling to
show latest transactions after send/swap operations

## **Related issues**

Fixes: https://consensyssoftware.atlassian.net/browse/TMCU-273

## **Manual testing steps**

```gherkin
Feature: Transaction list auto-scroll on new transaction

  Scenario: user completes a transaction and views Activity tab
    Given user is on the wallet home screen
    And user has existing transactions in their Activity list
    
    When user sends or swaps tokens
    And the transaction is submitted
    And user navigates to the Activity tab
    
    Then the Activity list should automatically scroll to the top
    And the new transaction should be visible at the top of the list
    
  Scenario: user is manually scrolling when new transaction arrives
    Given user is on the Activity tab
    And user is actively scrolling through their transaction history
    
    When a new transaction is detected
    
    Then the list should NOT auto-scroll
    And user should maintain their current scroll position
    
  Scenario: user resumes browsing after manual scroll
    Given user was manually scrolling
    And user has stopped scrolling for 1 second
    
    When a new transaction is added
    
    Then the list should auto-scroll to show the new transaction
```

## **Screenshots/Recordings**

Solana


https://github.com/user-attachments/assets/eff75cc9-0202-49bd-bf7b-bf54935b96ac

EVM


https://github.com/user-attachments/assets/6c38ca39-1e59-414b-adf2-22119b9336fd

TRX


https://github.com/user-attachments/assets/4cb4045b-ba71-44e9-8b58-6dd70585bb99

### **Before**


https://github.com/user-attachments/assets/8c3a08d8-bf37-4ac0-a391-1924ab308bff

### **After**


https://github.com/user-attachments/assets/c276f244-e7b3-417b-aaa0-d2b68816e479

## **Pre-merge author checklist**

- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I've included tests if applicable
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

- [x] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [x] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Touches core transaction list scrolling behavior; while guarded
against user interaction and errors, it could still introduce unexpected
scroll jumps or timing issues on some devices.
> 
> **Overview**
> **Unified Activity list now auto-scrolls to the top when new
transactions are added.** `UnifiedTransactionsView` wires a new
`useTransactionAutoScroll` hook into the `FlashList` `onScroll` handler
and uses a chain-agnostic `keyExtractor` (EVM `tx.id`, non-EVM `id` with
`chain-timestamp` fallback) to detect when the first item changes or the
list grows.
> 
> The new hook debounces auto-scroll with a small delay, avoids
scrolling while the user is actively scrolling, and includes timeout
cleanup plus error handling around ID extraction and `scrollToOffset`. A
comprehensive test suite was added to cover multi-chain behavior,
user-scroll suppression, configuration options, and edge cases.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
e80ae84. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…ame (#25592)

<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->

- fix capitalization typo in event name making it invalid agains Segment
Schema

## **Changelog**

<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`

If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`

(This helps the Release Engineer do their job more quickly and
accurately)
-->

CHANGELOG entry: null

## **Related issues**

Fixes: https://consensyssoftware.atlassian.net/browse/MCWP-319

## **Manual testing steps**

N/A

## **Screenshots/Recordings**

<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->

### **Before**

N/A

### **After**

N/A

## **Pre-merge author checklist**

- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I've included tests if applicable
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk string-only change to an analytics event label plus a
matching test update; no functional logic paths are modified.
> 
> **Overview**
> Fixes the `DEEP_LINK_USED` MetaMetrics event display name
capitalization from `Deep link Used` to `Deep Link Used` to align with
expected analytics/schema naming.
> 
> Updates `DeepLinkModal` test mocks to expect the corrected event name.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
7aedbd8. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**
This PR adds iOS Flask runs along side the existing Android ones. It
follows the same approach as Android does for the builds, taking
advantage of the main build and repacking it with the flask code.

The main`ci.yml` now passes in Built type and MetaMask environment as a
parameter and the build job now takes it and builds the corresponding
artifact.

iOS Flask passing run:
https://github.com/MetaMask/metamask-mobile/actions/runs/21626290091/job/62330880758

<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->

## **Changelog**

<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`

If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`

(This helps the Release Engineer do their job more quickly and
accurately)
-->

CHANGELOG entry:

## **Related issues**

Fixes: https://consensyssoftware.atlassian.net/browse/MMQA-1099

## **Manual testing steps**
No manual testing steps apply. 
iOS Flask passing run:
[MetaMask/metamask-mobile/actions/runs/21626290091/job/62330880758](https://github.com/MetaMask/metamask-mobile/actions/runs/21626290091/job/62330880758)

## **Screenshots/Recordings**

<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->

### **Before**
N/A
<!-- [screenshots/recordings] -->

### **After**
N/A
<!-- [screenshots/recordings] -->

## **Pre-merge author checklist**

- [x] I’ve followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I’ve included tests if applicable
- [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I’ve applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [x] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Changes CI orchestration and artifact naming for iOS builds, plus
alters iOS `bundleIdentifier` selection for `flask`, which could break
E2E pipelines or repack/signing if misconfigured.
> 
> **Overview**
> Adds an **iOS Flask E2E smoke-test lane** to CI, including a new
`run-e2e-smoke-tests-ios-flask.yml` workflow that repacks a `main` iOS
`.app` into a `flask` build and runs `FlaskBuildTests` shards.
> 
> Makes iOS E2E build/test workflows **parameterized by `build_type` and
`metamask_environment`**, updating artifact names and
`PREBUILT_IOS_APP_PATH` wiring so multiple iOS build variants can be
downloaded and executed in `run-e2e-workflow.yml`.
> 
> Updates app/test behavior to support the new lane: iOS
`bundleIdentifier` now switches for `METAMASK_BUILD_TYPE=flask`, and
Snap E2E tests include stability tweaks (Detox iOS WebSocket sync
disable, improved tap helper, and combined preinstalled-snap test to
reuse `mockServer`).
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
f96af0a. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
@pull pull Bot locked and limited conversation to collaborators Feb 3, 2026
@pull pull Bot added the ⤵️ pull label Feb 3, 2026
@pull pull Bot merged commit b78edac into Reality2byte:main Feb 3, 2026
1 of 10 checks passed
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.